#include <stdio.h>
#include <string.h>
#include "public.h"
#include "packet_capture.h"


int parse_packet(yx_pkt *pkt);
int handle_linklayer(yx_pkt *pkt);
int handle_netlayer(yx_pkt *pkt);


void *packet_handler(void *arg)
{
    afpacket_instance *p_ins = (afpacket_instance *)arg;
    yx_pkt pkt;
    pkt.rx = (afpacket *)malloc(sizeof(afpacket *));
    pkt.tx = (afpacket *)malloc(sizeof(afpacket *));
    pkt.rx->buf = malloc(sizeof(u_int8_t)*AF_MTU);
    pkt.tx->buf = malloc(sizeof(u_int8_t)*AF_MTU);
    bzero(pkt.rx->buf, AF_MTU);
    bzero(pkt.tx->buf, AF_MTU);
    printf("-------------------->invoke packet_handler------\n");
    while (1)
    {
        if (afpacket_poll(p_ins, &pkt, AF_MTU) == 0)
        {
            continue;
        }

        /* todo for packet */
        parse_packet(&pkt);
    }

    return NULL;
}


int main()
{
    afpacket_instance *p_ins = NULL;

    int ret = afpacket_init("eth0", (void **)&p_ins);
    if (ret == AF_FAILED)
    {
        goto finish;
    }

    if (afpacket_start(p_ins, 1) == AF_FAILED)
        goto finish;

    pthread_t th;
    ret = pthread_create(&th, NULL, packet_handler, (void *)p_ins);
    if (ret != 0)
    {
        printf("create thread packet_handler() failed !\n");
        goto finish;
    }
    pthread_join(th, NULL);


finish:
    printf("======================================>pkts_cap is terminating ....\n");
    return 0;
}


int parse_packet(yx_pkt *pkt)
{
    int ret = -1;
    if (pkt == NULL)
        return -1;

    u_int8_t *buf = pkt->rx->buf;
    struct ethhdr *p_ethh = (struct ethhdr *)buf;
    switch (p_ethh->h_proto)
    {
        case NET_VLAN_TAG:
            if (*((u_int16_t *)(buf+16)) != NET_TYPE_IP)
            {
                return -1;
            }
            pkt->rx->vlan_len = 4;
            ret = -1;
            break;

        case NET_TYPE_ARP:
            ret = handle_linklayer(pkt);
            break;
        case NET_TYPE_IP:
            ret = handle_netlayer(pkt);
            break;
        default:
            break;
    }

    return ret;
}

int handle_linklayer(yx_pkt *pkt)
{
    printf("===================>DataLink Layer packet: %dbyte\n", pkt->rx->len);
    return 0;
}

int handle_netlayer(yx_pkt *pkt)
{
    struct iphdr *iph = (struct iphdr *)(pkt->rx->buf + sizeof(struct ethhdr) + pkt->rx->vlan_len);
    u_int16_t iph_len = iph->ihl<<2;
    // u_int16_t ip_len = ntohs(iph->tot_len);
    pkt->rx->p_iphdr = (u_int8_t *)iph;
    pkt->rx->p_tranhdr = (u_int8_t *)(pkt->rx->p_iphdr + iph_len);

    char saddr[20] = {0};
    char daddr[20] = {0};
    struct in_addr addr;
    memset(&addr, 0, sizeof(addr));
    addr.s_addr = iph->saddr;
    strcpy(saddr, inet_ntoa(addr));
    memset(&addr, 0, sizeof(addr));
    addr.s_addr = iph->daddr;
    strcpy(daddr, inet_ntoa(addr));

    switch (iph->protocol)
    {
        case IPPROTO_TCP:
        {
            struct tcphdr *th = (struct tcphdr *)pkt->rx->p_tranhdr;
            // printf("th->dest=%d, th->source=%d, htons(22)=%d\n", th->dest, th->source, htons(22));
            if (th->dest == htons(22) || th->source == htons(22))
            {
                return -1;
            }
            printf("-------->|tcp packet| saddr:%s, daddr:%s, %dbyte\n", saddr, daddr, pkt->rx->len);
            break;
        }
        case IPPROTO_UDP:
            printf("-------->|udp packet| saddr:%s, daddr:%s, %dbyte\n", saddr, daddr, pkt->rx->len);
            break;
        case IPPROTO_ICMP:
            printf("-------->|icmp packet| saddr:%s, daddr:%s, %dbyte\n", saddr, daddr, pkt->rx->len);
            break;
        case IPPROTO_IGMP:
            printf("-------->|igmp packet| saddr:%s, daddr:%s, %dbyte\n", saddr, daddr, pkt->rx->len);
            break;
        default:
            return -1;
    }

    return 0;
}
